package org.codeart.price.service;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.codeart.common.dto.PriceRule;
import org.codeart.common.request.EstimatedPriceDTO;
import org.codeart.common.response.DirectionResponse;
import org.codeart.common.response.PriceResponse;
import org.codeart.common.util.BigDecimalUtil;
import org.codeart.common.util.R;
import org.codeart.price.mapper.PriceRuleMapper;
import org.codeart.price.remote.ServiceMapClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;

@Slf4j
@Service
public class PriceService {

    @Autowired
    private ServiceMapClient serviceMapClient;

    @Autowired
    private PriceRuleMapper priceRuleMapper;

    public PriceResponse estimatedPrice(String depLongitude, String depLatitude, String destLongitude,
                                        String destLatitude, String cityCode, String vehicleType) {
        log.info("出发地经度: {}", depLongitude);
        log.info("出发地纬度: {}", depLatitude);
        log.info("目的地经度: {}", destLongitude);
        log.info("目的地纬度: {}", destLatitude);
        log.info("调用地图服务，查询距离和时长");
        EstimatedPriceDTO estimatedPriceDTO = new EstimatedPriceDTO();
        estimatedPriceDTO.setDepLongitude(depLongitude)
                         .setDepLatitude(depLatitude)
                         .setDestLongitude(destLongitude)
                         .setDestLatitude(destLatitude);
        R<DirectionResponse> r = serviceMapClient.direction(estimatedPriceDTO);
        DirectionResponse data = r.getData();
        Integer distance = data.getDistance();
        Integer duration = data.getDuration();
        log.info("距离: {}", distance);
        log.info("时长: {}", duration);

        QueryWrapper<PriceRule> wrapper = new QueryWrapper<>();
        wrapper.lambda()
               .eq(PriceRule::getCityCode, cityCode)
               .eq(PriceRule::getVehicleType, vehicleType)
               .orderByDesc(PriceRule::getFareVersion);
        List<PriceRule> list = priceRuleMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return null;
        }

        PriceRule latest = list.get(0);
        log.info("读取计价规则: {}", latest);
        log.info("根据距离，时长和计价规则，计算价格");
        Double price = getPrice(distance, duration, latest);

        PriceResponse response = new PriceResponse();
        response.setCityCode(cityCode)
                .setPrice(price)
                .setVehicleType(vehicleType)
                .setFareType(latest.getFareType())
                .setFareVersion(latest.getFareVersion());
        return response;
    }
    
    public R<Double> calculatePrice(Integer distance, Integer duration, String cityCode, String vehicleType) {
        QueryWrapper<PriceRule> wrapper = new QueryWrapper<>();
        wrapper.lambda()
               .eq(PriceRule::getCityCode, cityCode)
               .eq(PriceRule::getVehicleType, vehicleType)
               .orderByDesc(PriceRule::getFareVersion);
        List<PriceRule> list = priceRuleMapper.selectList(wrapper);
        if (list.size() == 0) {
            return R.fail("计价规则不存在");
        }
        PriceRule priceRule = list.get(0);
        Double price = getPrice(distance, duration, priceRule);
        log.info("根据距离, 时长和计价规则, 计算价格, 总价格: {}", price);
        return R.ok(price);
    }

    /**
     * 根据距离、时长和计价规则来计算最终价格
     * @param distance  距离
     * @param duration  时长
     * @param priceRule 计价规则
     * @return 费用
     */
    public Double getPrice(Integer distance, Integer duration, PriceRule priceRule) {
        double price = 0;

        // 起步价
        double startFare = priceRule.getStartFare();
        price = BigDecimalUtil.add(price, startFare);

        // 里程费，总里程 m，转化为 km
        double distanceMile = BigDecimalUtil.divide(distance, 1000);

        // 起步里程
        double startMile = priceRule.getStartMile();
        double distanceSubtract = BigDecimalUtil.subtract(distanceMile, startMile);

        // 最终里程数
        double finalMile = distanceSubtract < 0 ? 0 : distanceSubtract;

        // 计程单价  元/km
        double unitPricePerMile = priceRule.getUnitPricePerMile();

        // 里程价
        double mileFare = BigDecimalUtil.multiply(finalMile, unitPricePerMile);
        price = BigDecimalUtil.add(price, mileFare);

        // 时长费，时长单位是 s 转化为 min
        double time = BigDecimalUtil.divide(duration, 60);
        double unitPricePerMinute = priceRule.getUnitPricePerMinute();

        // 时长费用
        double timeFare = BigDecimalUtil.multiply(time, unitPricePerMinute);
        price = BigDecimalUtil.add(price, timeFare);

        BigDecimal priceBigDecimal = BigDecimal.valueOf(price);
        return priceBigDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 添加计价规则
     * @param priceRule 计价规则
     * @return boolean
     */
    public boolean addPriceRule(PriceRule priceRule) {
        // 拼接fareType
        String cityCode = priceRule.getCityCode();
        String vehicleType = priceRule.getVehicleType();
        String fareType = cityCode + "$" + vehicleType;
        priceRule.setFareType(fareType);

        // 添加版本号
        QueryWrapper<PriceRule> wrapper = new QueryWrapper<>();
        wrapper.lambda()
               .eq(PriceRule::getCityCode, cityCode)
               .eq(PriceRule::getVehicleType, vehicleType)
               .orderByDesc(PriceRule::getFareVersion);  // 降序排列，取最大值
        List<PriceRule> list = priceRuleMapper.selectList(wrapper);
        int fareVersion = 0;
        if (list.size() > 0) {
            return false;
        }
        priceRule.setFareVersion(++fareVersion);

        int i = priceRuleMapper.insert(priceRule);
        return i != -1;
    }

    public boolean updatePriceRule(PriceRule priceRule) {
        String cityCode = priceRule.getCityCode();
        String vehicleType = priceRule.getVehicleType();
        String fareType = cityCode + "$" + vehicleType;
        priceRule.setFareType(fareType);

        QueryWrapper<PriceRule> wrapper = new QueryWrapper<>();
        wrapper.lambda()
               .eq(PriceRule::getCityCode, cityCode)
               .eq(PriceRule::getVehicleType, vehicleType)
               .orderByDesc(PriceRule::getFareVersion);  // 降序排列，取最大值
        List<PriceRule> list = priceRuleMapper.selectList(wrapper);
        Integer fareVersion = 0;
        if (list.size() > 0) {
            PriceRule latest = list.get(0);
            Double unitPricePerMile = latest.getUnitPricePerMile();
            Double unitPricePerMinute = latest.getUnitPricePerMinute();
            Double startFare = latest.getStartFare();
            Integer startMile = latest.getStartMile();

            if (unitPricePerMile.doubleValue() == priceRule.getUnitPricePerMile().doubleValue() &&
                unitPricePerMinute.doubleValue() == priceRule.getUnitPricePerMinute().doubleValue() &&
                startFare.doubleValue() == priceRule.getStartFare().doubleValue() &&
                startMile.intValue() == priceRule.getStartMile().intValue()) {
                return false;
            }
            fareVersion = latest.getFareVersion();
        }
        priceRule.setFareVersion(++fareVersion);
        priceRuleMapper.insert(priceRule);
        return true;
    }

    public boolean exists(PriceRule priceRule) {
        String cityCode = priceRule.getCityCode();
        String vehicleType = priceRule.getVehicleType();

        QueryWrapper<PriceRule> wrapper = new QueryWrapper<>();
        wrapper.lambda()
               .eq(PriceRule::getCityCode, cityCode)
               .eq(PriceRule::getVehicleType, vehicleType)
               .orderByDesc(PriceRule::getFareVersion);
        List<PriceRule> list = priceRuleMapper.selectList(wrapper);
        return list.size() > 0;
    }
    
    


}
